var jfJQMOffline = (function($, document, window) {
  'use strict';

  var $document = $(document),
      $window = $(window),
      isOnline = navigator.onLine;
  
  /************** Public interface ************************/
  var that = {
    
    clickEvent: 'vclick',
    
    showOfflineTeasers: function() {   
      var $page = $('#jfJQMOffline');
      if (!$page.length) {
        $page = $('<div data-role="dialog" id="jfJQMOffline"><div data-role="header"><h1>Offline Content</h1></div><div data-role="content"><ul data-role="listview" id="jfJQMOffline_teasers"></ul></div></div>');
        $page.appendTo($.mobile.pageContainer);
      }

      $.mobile.changePage($page);
      loadOfflineTeasers();
    },
    
    savePage: function($page) {
      $page = $page || $.mobile.activePage;
      if ($page.attr('data-jfJQMOffline-url')) {
        $.ajax({
          url: $page.attr('data-jfJQMOffline-url'),
          success: function(response) {
            var $page = $('<div>').html(response).find("div:jqmData(role='page')");
            if ($page.length) {
              $page.removeAttr('data-jfJQMOffline-url');
              that.savePage($page);
            }
          }
        });

        return;
      }
      
      $page.trigger(
        'pagebeforesave:jfJQMOffline',
        [
          normalizeUrl($page.jqmData('url')),
          { 
            title: getTeaserTitleForPage($page),
            teaserText: getTeaserTextForPage($page),
            content: getContentForPage($page)
          }
        ]
      );
    }

  };

  
  /************** Event Bindings ************************/
  if (window.localStorage && window.JSON) {
    $window.bind('online', onOnline);
      
    $document.
      bind('pagebeforechange', onPageBeforeChange).
      bind('pagebeforesave:jfJQMOffline', onPageBeforeSave).
      bind('pagesave:jfJQMOffline', onPageSave);
    
    $("div:jqmData(role='page')").live('pagebeforecreate' , onPageBeforeCreate);
  }

  
    
  /************** Private functions ************************/
  
  function onPageBeforeSave(e, url, data) {
    data.content = encodeContent(data.content);   
    $(e.target).trigger('pagesave:jfJQMOffline', [url, data]);
  }
  
  function onPageSave(e, url, data) {
    var storage = JSON.parse(window.localStorage.getItem('jfJQMOffline_content') || '{}');
    storage[url] = data;
    window.localStorage.setItem('jfJQMOffline_content', JSON.stringify(storage));
  }
  
  function onPageBeforeChange(e, data) {
    if (!isOnline && typeof data.toPage === 'string') {
      var offlineContent = getOfflineContent();
      var url = normalizeUrl(data.toPage);
      if (offlineContent[url]) {
        e.preventDefault();
        showPage(url, offlineContent[url]);
      }
    }
  }
  
  function onPageBeforeCreate(e) {
    var $page = $(this);
    $page.data('jfJQMOffline_pageContent', $('<div>').append($page.clone()).html()); //store html content before jQuery Mobile enhancement
  }
  
  function onOffline(e) {
    isOnline = false;
    that.showOfflineTeasers();
  }
  function onOnline(e) {
    isOnline = true;
  }

  function loadOfflineTeasers() {
    var $teasers = $('#jfJQMOffline_teasers'); 
    $teasers.empty();
    $.each(getOfflineContent(), function(url, item) {
      $('<li><h2>'+item.title+'</h2><p>'+item.teaserText+'</p></li>').
        css('cursor', 'pointer').
        bind(that.clickEvent, showPage.bind(null, url, item)).
        appendTo($teasers);
    });
    $teasers.listview();
    $teasers.listview('refresh');
    /*
    window.localStorage.setItem('jfJQMOffline_teasers', JSON.stringify([
      {headline: 'Headline Teaser 1', text: 'Headline Text 1'},
      {headline: 'Headline Teaser 2', text: 'Headline Text 2'}
    ]));
    */
  }
    
  function showPage(url, offlineContent) {
    var $page = $('div:jqmData(url="'+url+'")');
    if (!$page.length) {
      $page = $(offlineContent.content);
      $page.appendTo($.mobile.pageContainer);
    }
    $.mobile.changePage($page);
  }
  
  function getOfflineContent() {
    return window.JSON.parse(window.localStorage.getItem('jfJQMOffline_content') || '{}');
  }
  
  function normalizeUrl(url) {
    var parsed = $.mobile.path.parseUrl(url);
    return parsed.pathname+(parsed.search ? parsed.search : '');
  }

  function getTeaserTitleForPage($page) {
    return $page.attr('data-jfJQMOffline-teaserTitle') || $page.find('h1:first').html();
  }
  
  function getTeaserTextForPage($page) {
    return $page.attr('data-jfJQMOffline-teaserText') || $page.find('p:first').html();
  }
  
  function getContentForPage($page) {
    return $page.data('jfJQMOffline_pageContent') || $('div').append($page.clone()).html();
  }
  
  function encodeContent(content) {
    var $content = $(content);
    $content.find('img').each(function (idx, img) {
      $(img).attr('src', base64EncodeImage(img));
    });
    return $('<div>').append($content).html();
  }
  
  function base64EncodeImage(img) {
    var canvas = document.createElement('canvas');
    canvas.width = img.width;
    canvas.height = img.height;
    try {
      var ctx = canvas.getContext('2d');
      ctx.drawImage(img, 0, 0);
      
      var imgType = img.src.match(/(jpg|jpeg|png)/);
      if (imgType.length) {
        imgType = imgType[0] == 'jpg' ? 'jpeg' : imgType[0];
      }
      else {
        throw 'Invalid image type for canvas encoder.';
      }

      return canvas.toDataURL('image/' + imgType);
    }
    catch (e) {
      console && console.log(e);
      return 'error';
    }
  }
  
  return that;

})(jQuery, document, window);
